package com.atguigu.gulimall.product.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.atguigu.gulimall.product.entity.PmsCategoryBrandRelationEntity;
import com.atguigu.gulimall.product.service.PmsCategoryBrandRelationService;
import com.atguigu.gulimall.product.vo.Catalog3Vo;
import com.atguigu.gulimall.product.vo.Catelog2Vo;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;

import com.atguigu.gulimall.product.dao.PmsCategoryDao;
import com.atguigu.gulimall.product.entity.PmsCategoryEntity;
import com.atguigu.gulimall.product.service.PmsCategoryService;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;


@Service("pmsCategoryService")
public class PmsCategoryServiceImpl extends ServiceImpl<PmsCategoryDao, PmsCategoryEntity> implements PmsCategoryService {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;

    @Resource
    private PmsCategoryBrandRelationService categoryBrandRelationService;
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<PmsCategoryEntity> page = this.page(
                new Query<PmsCategoryEntity>().getPage(params),
                new QueryWrapper<PmsCategoryEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public List<PmsCategoryEntity> getTree() {
        //获取所有数据
         List<PmsCategoryEntity> list = this.list();
        List<PmsCategoryEntity> collect = list.stream().filter(pmsCategoryEntity -> pmsCategoryEntity.getParentCid() == 0
        ).map((menu) -> {
            menu.setChildren(getChildren(menu, list));
            return menu;
        }).sorted((menu, menu1) -> {
            return (menu.getSort() == null ? 0 : menu.getSort()) - (menu1.getSort() == null ? 0 : menu1.getSort());
        }).collect(Collectors.toList());
        return collect;
    }

    @Transactional
    @Override
    public void updateCategory(PmsCategoryEntity pmsCategory) {
        if(StringUtils.isNotBlank(pmsCategory.getName())){
            QueryWrapper<PmsCategoryBrandRelationEntity> queryWrapper=new QueryWrapper<>();
            //修改中间表名称
            PmsCategoryBrandRelationEntity categoryBrandRelationEntity=new PmsCategoryBrandRelationEntity();
            queryWrapper.eq("catelog_id",pmsCategory.getCatId());
            categoryBrandRelationEntity.setCatelogName(pmsCategory.getName());
            categoryBrandRelationService.update(categoryBrandRelationEntity,queryWrapper);
        }
        this.updateById(pmsCategory);
    }

    //使用redission分布式锁
    @Override
    public Map<String, List<Catelog2Vo>> getRedissonCatelogJson() {
        RLock categorysLock = redissonClient.getLock("categorysLock");
        categorysLock.lock(3,TimeUnit.MINUTES);
        Map<String, List<Catelog2Vo>> catelogJsonData;
        try{
            catelogJsonData= this.getCatelogJsonData();
        }finally {
            categorysLock.unlock();
        }
        return catelogJsonData;

    }


    //使用分布式锁
    @Override
    public Map<String, List<Catelog2Vo>> getCatelogJson() {
        String uuid= UUID.randomUUID().toString();
        Boolean lockFlag = redisTemplate.opsForValue().setIfAbsent("lock", uuid,30, TimeUnit.SECONDS);
        Map<String, List<Catelog2Vo>> catelogJsonData;
        if(lockFlag){
            try{
                catelogJsonData= this.getCatelogJsonData();
            }finally {
                String key=redisTemplate.opsForValue().get("lock");
                // 删除也必须是原子操作 Lua脚本操作 删除成功返回1 否则返回0
                String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
                redisTemplate.execute(new DefaultRedisScript<>(script,Long.class), Arrays.asList("lock"),uuid);
            }
            return catelogJsonData;

        }else{
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return getCatelogJson();
        }
    }



    public Map<String, List<Catelog2Vo>> getCatelogJsonData(){
            String categorys1 = redisTemplate.opsForValue().get("categorys");
            if(StringUtils.isNotBlank(categorys1)){
                System.out.println("查询redis缓存");
                Map<String, List<Catelog2Vo>> listMap1=JSON.parseObject(categorys1,new TypeReference<Map<String, List<Catelog2Vo>>>(){});
                return listMap1;
            }
            List<PmsCategoryEntity> entityList = baseMapper.selectList(null);
            System.out.println("查询数据库数据");
            // 查询所有一级分类
            List<PmsCategoryEntity> level1 = getCategoryEntities(entityList, 0L);
            Map<String, List<Catelog2Vo>> parent_cid = level1.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
                // 拿到每一个一级分类 然后查询他们的二级分类
                List<PmsCategoryEntity> entities = getCategoryEntities(entityList, v.getCatId());
                List<Catelog2Vo> catelog2Vos = null;
                if (entities != null) {
                    catelog2Vos = entities.stream().map(l2 -> {
                        Catelog2Vo catelog2Vo = new Catelog2Vo(v.getCatId().toString(), l2.getName(), l2.getCatId().toString(), null);
                        // 找当前二级分类的三级分类
                        List<PmsCategoryEntity> level3 = getCategoryEntities(entityList, l2.getCatId());
                        // 三级分类有数据的情况下
                        if (level3 != null) {
                            List<Catalog3Vo> catalog3Vos = level3.stream().map(l3 -> new Catalog3Vo(l3.getCatId().toString(), l3.getName(), l2.getCatId().toString())).collect(Collectors.toList());
                            catelog2Vo.setCatalog3List(catalog3Vos);
                        }
                        return catelog2Vo;
                    }).collect(Collectors.toList());
                }
                return catelog2Vos;
            }));

            String categoryJson=JSON.toJSONString(parent_cid);
            redisTemplate.opsForValue().set("categorys",categoryJson);
            return parent_cid;
    }


    /*
     * 第一次查询的所有 CategoryEntity 然后根据 parent_cid去这里找
	 */
    private List<PmsCategoryEntity> getCategoryEntities(List<PmsCategoryEntity> entityList, Long parent_cid) {

        return entityList.stream().filter(item -> item.getParentCid() == parent_cid).collect(Collectors.toList());
    }


    public List<PmsCategoryEntity> getChildren(PmsCategoryEntity pmsCategoryEntity,List<PmsCategoryEntity> list){
        List<PmsCategoryEntity> collect = list.stream().filter(pmsCategoryEntity1 -> {
            return pmsCategoryEntity1.getParentCid() == pmsCategoryEntity.getCatId();
        }).map(pmsCategoryEntity1 -> {
            pmsCategoryEntity1.setChildren(getChildren(pmsCategoryEntity1, list));
            return pmsCategoryEntity1;
        }).sorted((menu, menu1) -> {
            return (menu.getSort() == null ? 0 : menu.getSort()) - (menu1.getSort() == null ? 0 : menu1.getSort());
        }).collect(Collectors.toList());
        return collect;
    }

}